perm filename TELNET.MID[NET,MRC]3 blob
sn#329148 filedate 1978-01-10 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00026 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00003 00002 TITLE TELNET
C00006 00003 Data area
C00009 00004 TELNET protocol codes
C00012 00005 Interrupt server
C00014 00006 Start of program
C00016 00007 Check for net-hoppers.
C00018 00008 Top level
C00021 00009 Process host specification
C00024 00010 Host name specified, ask magical routine to find it
C00026 00011 ICP ICP ICP
C00028 00012 Main program loop
C00031 00013 TTY input interrupt
C00034 00014 Network input interrupt
C00037 00015 IAC service
C00039 00016 IAC WILL/WONT
C00041 00017 IAC DO/DONT
C00043 00018 Character commands
C00045 00019 Protocol command service routines
C00047 00020 Connection command service routines
C00049 00021 Append file hacking
C00052 00022 Output file hacking
C00054 00023 Input file hacking
C00056 00024 Call DDT if there is a DDT present
C00057 00025 Filespec input routine.
C00059 00026 Sixbit & numeric TTY I/O
C00062 ENDMK
C⊗;
TITLE TELNET
SUBTTL Definitions
; Mark Crispin, SU-AI, January 1978
; Assembly switches
IFNDEF NPRSKT,NPRSKT==27 ; default ICP socket
IFNDEF HSTNLN,HSTNLN==10. ; host name buffer length
IFNDEF PDLLEN,PDLLEN==50. ; PDL length
IFNDEF TTOBFL,TTOBFL==50. ; TTY output buffer length
IFNDEF CLKSPD,CLKSPD==2. ; number of seconds between clock ints
; AC definitions. 0→3 (and, at HSTNAM, 4→11) are used by NETWRK.
; 0 is also used as very temp in the main program.
; X, Y, Z, A, and B are in approximate descending order of usage.
X=4 ? Y=5 ? Z=6 ? A=7 ? B=10 ? P=17
; I/O channels. NETWRK uses 0 and 1.
DSI==2 ? DSO==3
; Macro to send a TELNET command
DEFINE TELCMD CMDLST
SKIPE DEBUGP
OUTSTR [ASCIZ/⊗!CMDLST!*
/]
IRPS CMD,,CMDLST
MOVEI CMD
PUSHJ 17,NETOCH
TERMIN
PUSHJ 17,NETSND
TERMIN
; SAIL system bit definitions
INTTTY==020000,, ; TTY input interrupt
INTCLK==000200,, ; clock interrupt
DISLIN==400000,, ; III
DMLIN== 040000,, ; DM
DDDLIN==020000,, ; DD
PTYLIN==004000,, ; PTY
IMPBIT==001000,, ; IMP TTY
SPCBRK==000100,, ; special activation mode
BSACT== 000020 ; activate on backspace
; Include wonderful network routines
NIORTS==-1 ; include I/O routines
ERRHAN==-1 ; include automagic error handling
ERRINS==IF1,[0] .ELSE JRST CONERR ; error instruction
ERRTNS==-1 ; include error routines
HSTTAB==-1 ; include host table routines
.INSRT NETWRK[NET,MRC]
SUBTTL Data area
CORBEG==.
FSPBLK: BLOCK 4 ; filespec block
INPFLN: BLOCK 1 ; input filename stuff
INPEXT: BLOCK 1
INPPPN: BLOCK 1
OUTFLN: BLOCK 1 ; output filename stuff
OUTEXT: BLOCK 1
OUTPPN: BLOCK 1
; Flags
TTINTP: BLOCK 1 ; -1 → TTI interrupt
NTINTP: BLOCK 1 ; -1 → NTI interrupt
NTOINP: BLOCK 1 ; ≤ -1 → output should be flushed
CLSINP: BLOCK 1 ; -1 → connection closing
ISLURP: BLOCK 1 ; -1 → in input slurping mode
NTBFOP: BLOCK 1 ; -1 → something in net buffer
NETCMP: BLOCK 1 ; -1 → network command in progress
INPFLP: BLOCK 1 ; -1 → input file opened
SLOWFP: BLOCK 1 ; -1 → input in slow mode
OUTFLP: BLOCK 1 ; -1 → output file opened
CHARMP: BLOCK 1 ; -1 → in character mode
IRPS OPT,,WILL WONT DO DONT
OPT!P: BLOCK 1 ; -1 → option in effect
TERMIN
; Connection option flags
RCBINP: BLOCK 1 ; -1 → receiving binary
TRBINP: BLOCK 1 ; -1 → transmitting binary
ECHOP: BLOCK 1 ; -1 → remote echoing
SUPGAP: BLOCK 1 ; -1 → suppressing GA
; Buffer headers
DSIBF: BLOCK 3 ; disk input buffer
DSOBF: BLOCK 3 ; disk output buffer
; TTY buffer stuff
TTOBFR: BLOCK TTOBFL ; TTY output buffer
TTOCTR: BLOCK 1 ; TTY output counter
TTOPTR: BLOCK 1 ; TTY output pointer
COREND==.-1
; Stuff set in once only code and protected for restart zapping.
; Other buffers
PDL: BLOCK PDLLEN ; pushdown list
HSPBUF: BLOCK HSTNLN ; host argument stored here
HNMBUF: BLOCK HSTNLN ; host name stored here
; Other flags
DEBUGP: BLOCK 1 ; -1 → MRC is fooling around
DPYP: BLOCK 1 ; -1 → display terminal
PTYP: BLOCK 1 ; -1 → on a PTY
MONCMP: BLOCK 1 ; -1 → monitor command
ESCHAR: ↑↑ ; escape character for printing consoles
SUBTTL TELNET protocol codes
DEFINE TPC CODE
CODE
IRPS NAME,,CODE
[ASCIZ/NAME/]
.ISTOP
TERMIN
TERMIN
; Top level codes
TPLTAB:
TPC SE==240. ; subnegotiation end
TPC NOP==241. ; no-op
TPC DM==242. ; data mark
TPC BRK==243. ; break key
TPC IP==244. ; interrupt process
TPC AO==245. ; abort output
TPC AYT==246. ; are you there?
TPC EC==247. ; erase character
TPC EL==248. ; erase line
TPC GA==249. ; go ahead
TPC SB==250. ; subnegotiation
TPC WILL==251. ; sender will do
TPC WONT==252. ; sender won't do
TPC DO==253. ; receiver asked to do
TPC DONT==254. ; receiver must not do
TPC IAC==255. ; interpret as command
TPLMIN==400-<.-TPLTAB>
; Various WILL/WONT/DO/DONT options
WDOTAB:
TPC TRNBIN==0. ; transmit binary
TPC ECHO==1. ; echo
TPC RCP==2. ; reconnect
TPC SUPRGA==3. ; suppress GA
TPC NAMS==4. ; negotiate approx. message size
TPC STATUS==5. ; status option
TPC TIMMRK==6. ; timing mark
TPC RCTE==7. ; remote controlled trans/echo
TPC NAOL==8. ; negotiate output line width
TPC NAOP==9. ; negotiate page size
TPC NAOCRD==10. ; negotiate output CR
TPC NAOHTS==11. ; negotiate output horizontal tab stops
TPC NAOHTD==12. ; negotiate output HT
TPC NAOFFD==13. ; negotiate output FF
TPC NAOVTS==14. ; negotiate output vertical tab stops
TPC NAOVTD==15. ; negotiate output VT
TPC NAOLFD==16. ; negotiate output LF
TPC EXTASC==17. ; Tovar's idea of extended ASCII
TPC LOGOUT==18. ; logout option
TPC BM==19. ; byte macro
TPC DET==20. ; data entry terminal option
TPC SUPDUP==21. ; SUPDUP (not TELNET) protocol
WDOMAX==.-WDOTAB-1
TPC EXOPL==255. ; extended options
SUBTTL Interrupt server
; Interrupts only set flags which the main program (normally in INTW⊗
; state) looks at. Clock interrupts fake the world since it is possible
; to lose an interrupt otherwise. A network status change interrupt
; fakes an input interrupt so that everything typed ahead still is read.
INTSER: SKIPN X,JOBCNI ; get interrupt status
FATAL Null interrupt
TLNE X,(INTCLK) ; clock int fakes TTI and NTI
TLO X,(INTTTY\INTINP)
TLNE X,(INTTTY) ; TTI int
SETOM TTINTP
TLNE X,(INTINP) ; NTI int
SETOM NTINTP
TLNE X,(INTIMS) ; status change
SETOM CLSINP
TLNN X,(INTINR)
JRST INTSR1
SKIPE DEBUGP
OUTSTR [ASCIZ/*INR*
/]
DISMIS
INTSR1: TLNN X,(INTINS) ; IMP INS int
DISMIS
SOSL NTOINP
JRST INTSR2 ; dismiss interrupt
; Network interrupt, abort all TTY output!
MOVEI X,5*TTOBFL-1 ; reset TTY buffer counter
MOVEM X,TTOCTR
MOVE X,[440700,,TTOBFR] ; reset TTY buffer pointer
MOVEM X,TTOPTR
SETZM X,TTOBFR ; and zap buffer while at it
MOVE X,[TTOBFR,,TTOBFR+1]
BLT X,TTOBFR+TTOBFL-1
INTSR2: SKIPE DEBUGP
OUTSTR [ASCIZ/*INS*
/]
DISMIS ; dismiss interrupt
SUBTTL Start of program
TELNET: JFCL
RESET
SETZM MONCMP
; Scan monitor command line.
RESCAN X
JUMPLE X,CHKTTY ; no command to scan
INCHRS X
JRST CHKTTY ; goddam bagbiting lying monitor
TRZ X,"a#"A ; uppercaseify if necesary
CAIE X,"N
CAIN X,"T
SKIPA Y,[" ] ; TELNET or NTELNET command, scan for space
MOVEI Y,"; ; some other command, use semicolon
SCNARG: INCHRS X
JRST CHKTTY
CAIE X,↑J
CAIN X,175
JRST CHKTTY ; end of command line
CAIE X,(Y)
JRST SCNARG
SETOM MONCMP
; Gobble down host name from monitor command here
SETZM HSPBUF
MOVE [HSPBUF,,HSPBUF+1]
BLT HSPBUF+HSTNLN-1
MOVE Y,[440700,,HSPBUF]
MOVEI Z,5*HSTNLN
SCNAR1: INCHWL X
CAIE X,<" >
CAIN X,↑M
JRST SCNAR1
CAIE X,↑J
CAIN X,175
JRST CHKTTY
IDPB X,Y ; save character in buffer
SOJG Z,SCNAR1
SCNAR2: INCHWL X ; flush extra characters
CAIE X,↑J
CAIN X,175
JRST CHKTTY
JRST SCNAR2 ; what a loser
; Paw over terminal characteristics
CHKTTY: SETZM DPYP
HRROI [003000,,Y]
TTYSET ; get line characteristics
CAMN Y,[-1]
EXIT ; how can I work if detached?
TLNE Y,(DISLIN\DMLIN\DDDLIN) ; display?
SETOM DPYP
TLNE Y,(PTYLIN)
SETOM PTYP
; (continued on next page)
; Check for net-hoppers.
TLNE Y,(IMPBIT) ; check for net hoppers
JRST NETHOP
SKIPN MONCMP
JRST GETHST ; not command; prompt for host
JRST GETHS1 ; no host prompt
; This loser is net hopping!
NETHOP: OUTSTR [ASCIZ/Foo you are a net hopper.
/]
SKIPN MONCMP
JRST GETHST ; no further hassle if not command
OUTSTR [ASCIZ/
You are logged into SAIL over the ARPAnet. It is a waste of SAIL's
limited system resources (jobs, network links, etc.) to go back again
over the same network. It also greatly slows down response to you
and increases the chances of lossage due to a system or network failure.
You should not do this unless you have a good reason to do so. If you
have any questions, please contact MRC and LES for more information.
Thank you for your co-operation.
Are you SURE you want to TELNET now?/]
INCHRW
ANDI 137
CAIE "Y
EXIT
OUTSTR [ASCIZ/
/]
JRST GETHS1 ; continue monitor command
SUBTTL Top level
TOPLEV: SKIPE MONCMP ; called from monitor level?
JRST BYEBYE ; yes, bye bye
GETHST: OUTSTR [ASCIZ/Host = /]
; Set up the world
GETHS1: RESET ; clear all I/O
MOVE JOBFF
CORE ; smallify
JFCL
SETZM CORBEG
MOVE [CORBEG,,CORBEG+1]
BLT COREND ; zak!
MOVE P,[PDL(-PDLLEN)] ; set up stack pointer
OPEN DSI,[0 ? 'DSK,, ? DSIBF] ; get a disk input channel
FATAL DSK OPEN failed
OPEN DSO,[0 ? 'DSK,, ? DSOBF,,] ; get a disk output channel
FATAL DSK OPEN failed
SETACT [[ 777777,,777777 ; activate on everything
777777,,777777 ; just set it up for when we need it
777777,,777777
777777,,600000\BSACT]]
SETZM HOST
MOVEI NPRSKT
MOVEM ICPSKT
; Now preprocess the host name
SKIPE MONCMP
JRST GOTHST ; already set up
SETZM HSPBUF
MOVE [HSPBUF,,HSPBUF+1]
BLT HSPBUF+HSTNLN-1
MOVE Y,[440700,,HSPBUF]
MOVEI Z,5*HSTNLN
GETHCH: INCHWL X
CAIN X,775 ; αβALT is magic
PUSHJ P,DDTCAL
ANDI X,177
CAIE X,<" >
CAIN X,↑M
JRST GETHCH
CAIE X,↑J
CAIN X,175
JRST GOTHST
IDPB X,Y ; save character in buffer
SOJG Z,GETHCH
FLSHEX: INCHWL X ; flush extra characters
CAIN X,775 ; αβALT is magic
PUSHJ P,DDTCAL
ANDI X,177
CAIE X,↑J
CAIN X,175
JRST GOTHST
JRST FLSHEX ; what a loser
SUBTTL Process host specification
GOTHST: MOVE HSPBUF
ANDCM [<ASCII/XXX/>#<ASCII/xxx/>]; convert cases
CAME [ASCII/NSW/] ; happy Geoff
JRST NOTNSW
MOVE [ASCII/33@SR/]
MOVEM HSPBUF
MOVE [ASCII/I-KA/]
MOVEM HSPBUF+1
NOTNSW: MOVE Y,[440700,,HSPBUF]
MOVE Z,[440700,,HNMBUF]
ILDB X,Y ; first character tells it all
JUMPE X,TOPLEV
CAIL X,"0
CAIL X,"9
JRST ALPHST ; alphabetic host specification
PUSHJ P,SWINIR ; get socket or host number
JUMPE X,GOTHSN ; end of spec, host number
SKIPL A ; octal has priority over decimal
MOVE B,A
JUMPLE B,[ OUTSTR [ASCIZ/Illegal socket number
/]
CLRBFI
JRST TOPLEV]
MOVEM B,ICPSKT
CAIE X,",
CAIN X,"@
JRST HSTSPC
OUTSTR [ASCIZ/Illegal character in socket number
/]
CLRBFI
JRST TOPLEV
; Host specification
HSTSPC: ILDB X,Y ; first character must be numeric
JUMPE X,HSTLUZ
CAIL X,"0
CAIL X,"9
JRST ALPHST
PUSHJ P,SWINIR ; get socket
GOTHSN: SKIPL A
MOVE B,A
JUMPLE B,[ OUTSTR [ASCIZ/Illegal host number
/]
CLRBFI
JRST TOPLEV]
MOVEM B,HOST
JUMPE X,GOICP ; end of spec
HSTLUZ: OUTSTR [ASCIZ/Illegal character in host number
/]
CLRBFI
JRST TOPLEV
; Alphabetic host specification
ALPHST: IDPB X,Z ; copy spec into block for HSTNAM
JUMPE X,CHKHNM
ILDB X,Y
JRST ALPHST
; Host name specified, ask magical routine to find it
CHKHNM: PUSHJ P,MAPHST ; bring host table in core
SKIPE HOST ; host name waiting?
JRST [ PUSHJ P,HSTNUM ; no, just try and get an HDB
TDZA 2,2 ; no HDB, set up as nothing
JRST GOTHDB ; won with HDB
MOVEI 1,[ASCIZ/RANDOM-PLACE/]
JRST GOTHDB] ; continue with fake HDB
MOVEI HNMBUF
PUSHJ P,HSTNAM ; get descriptor block for the host
JRST [ OUTSTR [ASCIZ/No such host.
/]
PUSHJ P,UNMHST
CLRBFI
JRST TOPLEV]
JRST [ OUTSTR [ASCIZ/Ambiguous host name.
/]
PUSHJ P,UNMHST
CLRBFI
JRST TOPLEV]
MOVEM HOST
GOTHDB: TLNN 1,-1 ; any system spec?
JRST NOSYS ; unknown system
MOVE ICPSKT
CAIE NPRSKT
JRST NOSYS ; don't flush line editor if not TELNET
HLRZ X,1
MOVE (X)
CAME [ASCII/ITS/] ; if an ITS,
NOSYS: SKIPN DPYP ; or not a display
PUSHJ P,ECHATM ; use character mode
PUSHJ P,UNMHST ; flush host table
SUBTTL ICP ICP ICP
GOICP: PTJOBX [0 ? 3] ; local echo off
OUTSTR [ASCIZ/ Trying... /]
PUSH P,ICPSKT ; for check below
PUSHJ P,CONECT ; call wonderful ICPer
OUTSTR [ASCIZ/Open
/]
; Initialize interrupts
MOVEI INTSER
MOVEM JOBAPR ; set up interrupt server
CLKINT 60.*CLKSPD ; start the ticking clock
MOVSI (INTTTY\INTCLK\INTINS\INTINR\INTIMS\INTINP)
INTENB ; enable interrupts
LOCK ; prevent swapouts
; If new protocol, flush cretin GA's (we refuse to implement 'em) and try to
; get local echoing.
POP P, ; get ICP socket we used
CAIE NPRSKT ; new protocol?
JRST GOICP1 ; may be an FTP or something
SNEAKS
JRST GOICP0
CAIN 700 ; if αβ@ typed ahead
SETOM DEBUGP ; MRC is fooling around!
GOICP0: TELCMD [IAC DO ECHO IAC DO SUPRGA]
SETOM ECHOP ? SETOM SUPGAP
; Initialize TTY output buffer variables and randomness
GOICP1: MOVEI 5*TTOBFL-1 ; set up TTY buffer counter
MOVEM TTOCTR
MOVE [440700,,TTOBFR] ; set up TTY buffer pointer
MOVEM TTOPTR
SETZM TTOBFR
MOVE [TTOBFR,,TTOBFR+1]
BLT TTOBFR+TTOBFL-1
INSKIP
JRST SLEEPR
SETOM TTINTP
; (continued on next page)
SUBTTL Main program loop
SLEEPR: SKIPL INPFLP ; unless input file open,
IWAIT ; sleep for an interrupt
SLEPR1: AOSG TTINTP ; TTY int?
JRST TTISER
SKIPN CLSINP ; if closing, keep trying input till lossage
AOSG NTINTP ; NTI int?
JRST NTISER
SKIPL INPFLP ; input file open?
JRST SLEEPR
GETDCH: SOSG DSIBF+2
IN DSI,
CAIA
JRST [ CLOSE DSI,
PUSHJ P,NETSND
OUTSTR [ASCIZ/End of input file /]
MOVE X,INPFLN
PUSHJ P,OUTSIX
OUTCHR [".]
MOVE X,INPEXT
PUSHJ P,OUTSIX
OUTCHR ["[] ;]
HLLZ X,INPPPN
PUSHJ P,OUTSIX
OUTCHR [",]
HRLZ X,INPPPN
PUSHJ P,OUTSIX
OUTSTR [ASCIZ/].
/]
SETZM INPFLP
JRST SLEEPR]
ILDB DSIBF+1
JUMPE GETDCH
SKIPE SLOWFP ; nice slow file processing?
JRST CHRHAK ; yah, force on every character
; Duplicate of TTYSER's CHRHAK to avoid a force on each character
SKIPN ECHOP ; echo if in local mode
OUTCHR ; (this way avoids command echoing)
; Canonicalize from SAIL to standard ASCII
CAIN 175 ; ALT
MOVEI 33
CAIN 176 ; }
MOVEI 175
CAIN 32 ; ~
MOVEI 176
; Here to actually send the character
PUSHJ P,NETOCH ; output the character
JRST SLEPR1
; Here if connection is losing
CONERR: SKIPE CLSINP ; not closing?
SKIPE ISLURP ; error in slurping?
JRST TOPLEV ; yes, back to top level
JRST NTISER ; no, start slurping
; TTY input interrupt
TTISER: INCHSL ; get a character
JRST [ AOSG NTBFOP ; anything in the buffer?
PUSHJ P,NETSND ; force it out
AOSG NTINTP ; TTI buffer empty
JRST NTISER ; but some net stuff to handle
JRST SLEEPR]
; Command and mapping stuff. We only map between our character set and
; ASCII. Anybody who wants mapping to MIT's character set should use SUPDUP!!
CAIN 612 ; αβLF?
JRST [ MOVEI ↑Z ; probably ↑Z on a loser
SKIPN PTYP
JRST TTISR1 ; whatever
JRST CHRHAK] ; on a PTY it is ~!!!
SKIPN DPYP ; no ↑↑ processing if a display
JRST [ CAME ESCHAR
JRST .+1 ; not escape character
INCHRW
CAMN ESCHAR ; meta?
JRST [ INCHRW
CAMN ESCHAR ; control-meta?
JRST [ INCHRW
IORI 600; form αβcharacter
JRST .+1]
IORI 400 ; form βcharacter
JRST .+1]
IORI 200 ; form αcharacter
JRST .+1]
CAIN 775 ; αβALT is magic
PUSHJ P,DDTCAL
CAIN 777 ; αβBS?
JRST [ MOVEI 177 ? JRST TTISR1]; just an ordinary character
TRZE 400 ; META set?
JRST [ LDB X,[000700,,0] ; get ASCII part
CAILE X,"←
SUBI X,"a-"A ; uppercaseify if necessary
SUBI X,"@
JUMPL X,NTISER ; no op character
TRNN 200 ; CONTROL?
SKIPA X,CMCDSP(X) ; no, use right half
HLR X,CMCDSP(X) ; yes, use left half
PUSHJ P,(X)
JRST TTISER]
TRZE 200 ; if CONTROL is set
JRST [ TRZ 140 ; convert to canonical ASCII control
JRST TTISR1]
; Here only if an ASCII printing character
CHRHAK: SKIPN ECHOP ; echo if in local mode
OUTCHR ; (this way avoids command echoing)
; Canonicalize from SAIL to standard ASCII
CAIN 175 ; ALT
MOVEI 33
CAIN 176 ; }
MOVEI 175
CAIN 32 ; ~
MOVEI 176
; Here to actually send the character
TTISR1: PUSHJ P,NETOCH ; output the character
SETOM NTBFOP ; flag there is network output
JRST TTISER
; Network input interrupt
NTISER: SKIPE CLSINP ; closing?
JRST [ SKIPN ISLURP ; in slurp mode?
JSP X,[SETOM ISLURP ; tell CONERR we are slurping
OUTSTR TTOBFR ; output what was in buffer first
JRST (X)]
PUSHJ P,NETICW ; slurp slurp slurp
JRST NTISR2]
AOSG TTINTP
JRST [ SETOM NTINTP ; make sure we come back here
JRST TTISER] ; give the TTY a chance!
PUSHJ P,NETICH ; get a character
JRST [ OUTSTR TTOBFR
MOVEI 5*TTOBFL-1 ; reset TTY buffer counter
MOVEM TTOCTR
MOVE [440700,,TTOBFR] ; reset TTY buffer pointer
MOVEM TTOPTR
SETZM TTOBFR
MOVE [TTOBFR,,TTOBFR+1]
BLT TTOBFR+TTOBFL-1
AOSG TTINTP
JRST TTISER ; TTI int to be taken care of
JRST SLEEPR] ; else sleep
NTISR2: AOSG NETCMP ; IAC in progress?
JRST IACSER
IRPS OPT,,WILL WONT DO DONT
AOSG OPT!P
JRST OPT!SR
TERMIN
CAIN IAC ; network command?
JRST [ SETOM NETCMP ; remember that one is coming
JRST NTISER]
NTISR1: JUMPE NTISER ; flush nulls
CAIN 176 ; ~
MOVEI 32
CAIN 175 ; }
MOVEI 176
CAIN 33 ; diamond
MOVEI 175
CAIN ↑G
JRST [ HRROI -1
BEEP
JRST NTISER] ; map bells to bells
CAIN 177 ; rubout is usually padding
JRST NTISER
SKIPGE NTOINP ; no output if still output reset
JRST NTISR3
SKIPE ISLURP
JRST [ OUTCHR ; slurp mode can't buffer
JRST NTISR3] ; since it can die at any time!
SOSG TTOCTR ; buffer stuffed?
JRST [ OUTSTR TTOBFR
MOVEI X,5*TTOBFL-1 ; set up TTY buffer counter
MOVEM X,TTOCTR
MOVE X,[440700,,TTOBFR] ; set up TTY buffer pointer
MOVEM X,TTOPTR
SETZM TTOBFR
MOVE X,[TTOBFR,,TTOBFR+1]
BLT X,TTOBFR+TTOBFL-1
JRST .+1]
IDPB TTOPTR
NTISR3: SKIPL OUTFLP ; output file in progress?
JRST NTISER
SOSG DSOBF+2
OUTPUT DSO,
IDPB DSOBF+1
JRST NTISER
SUBTTL IAC service
IACSER: CAIN IAC ; quoted IAC?
JRST NTISR1 ; just send it
SKIPE DEBUGP
PUSHJ P,TPLMSG
CAIN DM ; data mark?
JRST [ AOS NTOINP
JRST NTISER]
IRPS OPT,,WILL WONT DO DONT
CAIN OPT
JRST [SETOM OPT!P
JRST NTISER]
TERMIN
CAIN SB
WARN Foreign host sent a subnegotiation
JRST NTISER ; not an option I know
; Protocol command message for MRC's fooling around
TPLMSG: OUTSTR [ASCIZ/*IAC /]
CAIGE TPLMIN ; big enough?
JRST @RNDMSG
MOVE 1,
OUTSTR @TPLTAB-TPLMIN(1)
CAIGE WILL
OUTSTR [ASCIZ/*
/]
POPJ P,
; WILL/WONT/DO/DONT option message for MRC's fooling around
OPTMSG: CAIN EXOPL
JRST [ OUTSTR [ASCIZ/ EXOPL*
/]
POPJ P,]
OUTCHR [" ]
CAILE WDOMAX
RNDMSG: JRST [ IDIVI 100
ADDI "0
OUTCHR
IDIVI 10
ADDI 1,"0
OUTCHR 1
ADDI 2,"0
OUTCHR 2
OUTSTR [ASCIZ/*
/]
POPJ P,]
MOVE 1,
OUTSTR @WDOTAB(1)
OUTSTR [ASCIZ/*
/]
POPJ P,
; IAC WILL/WONT
WILLSR: SKIPE DEBUGP
PUSHJ P,OPTMSG
CAIN TRNBIN ; binary from host
JRST [ SKIPE RCBINP ; catch protocol loops
JRST NTISER
SETOM RCBINP
TELCMD [IAC DO TRNBIN]
JRST NTISER]
CAIN ECHO ; remote echo (what a win!)
JRST [ SKIPE ECHOP ; catch protocol loops
JRST NTISER
SETOM ECHOP
TELCMD [IAC DO ECHO]
JRST NTISER] ; command, we always accept it
CAIN SUPRGA ; suppress GA?
JRST [ SKIPE SUPGAP ; command or reply?
JRST NTISER
SETOM SUPGAP
TELCMD [IAC DO SUPRGA]
JRST NTISER]
; Not an option we like, refuse it
PUSH P,
SKIPE DEBUGP
OUTSTR [ASCIZ/⊗IAC DONT/]
MOVEI IAC
PUSHJ P,NETOCH
MOVEI DONT
PUSHJ P,NETOCH
POP P,
SKIPE DEBUGP
PUSHJ P,OPTMSG
PUSHJ P,NETOCH
PUSHJ P,NETSND
JRST NTISER
WONTSR: SKIPE DEBUGP
PUSHJ P,OPTMSG
CAIN TRNBIN
JRST [ SKIPN RCBINP
JRST NTISER
SETZM RCBINP
TELCMD [IAC DONT TRNBIN]
JRST NTISER]
CAIN ECHO
JRST [ SKIPN ECHOP
JRST NTISER
SETZM ECHOP ; back to lossage
TELCMD [IAC DONT ECHO]
JRST NTISER]
CAIN SUPRGA
SKIPL SUPGAP
JRST NTISER ; protocol violator
SETZM SUPGAP
TELCMD [IAC DONT SUPRGA]
JRST NTISER ; loser
; IAC DO/DONT
DOSR: SKIPE DEBUGP
PUSHJ P,OPTMSG
CAIN TRNBIN ; binary to host
JRST [ SKIPE TRBINP ; catch protocol loops
JRST NTISER
SETOM TRBINP
TELCMD [IAC WILL TRNBIN]
JRST NTISER]
CAIN TIMMRK ; silly Multix and Tenex cretinism?
JRST [ TELCMD [IAC WILL TIMMRK]
JRST NTISER] ; yes, make the losers happy
; Not an option we like, refuse it
PUSH P,
SKIPE DEBUGP
OUTSTR [ASCIZ/⊗IAC WONT/]
MOVEI IAC
PUSHJ P,NETOCH
MOVEI WONT
PUSHJ P,NETOCH
POP P,
SKIPE DEBUGP
PUSHJ P,OPTMSG
PUSHJ P,NETOCH
PUSHJ P,NETSND
JRST NTISER
DONTSR: SKIPE DEBUGP
PUSHJ P,OPTMSG
CAIN TRNBIN
SKIPN TRBINP
JRST NTISER
SETZM TRBINP
TELCMD [IAC WONT TRNBIN]
JRST NTISER
SUBTTL Character commands
; Command dispatch table
CMCDSP: REPEAT 40,[NTISER,,NTISER ? ] ; default to no-op
DEFINE CMDCHR CHR,CDISP,DISP
LOC CMCDSP+"CHR-"@
CDISP,,DISP
TERMIN
; Command dispatch table. All routines are assumed to return via POPJ P,
; CMDCHR character,αβdispatch,βdispatch
CMDCHR @,DBUG,NDBUG ; MRC fooling around
CMDCHR A,ATTN,ATTN ; send ATTN
CMDCHR B,BREAK,BREAK ; send BRK
CMDCHR C,CLSCON,CLSCON ; close connection
CMDCHR D,CLSOFL,OPNOFL ; output file
CMDCHR E,RECHO,LECHO ; echo mode
CMDCHR F,APPEND,DAPPND ; append file
CMDCHR I,CLSIFL,OPNIFL ; input file
CMDCHR J,EOFF,EON ; echo diddle without telling host
CMDCHR L,ECHATM,LCHATM ; line editor diddle
CMDCHR O,ABORTO,ABORTO ; abort output
CMDCHR Q,PUNT,PUNT ; exit
CMDCHR R,CLSIFL,OPNIFS ; open file in nice slow way
CMDCHR W,RUTHER,RUTHER ; are you there?
CMDCHR X,ESCSET,ESCSET ; set escape character
LOC CMCDSP+40
SUBTTL Protocol command service routines
; Send ATTN
ATTN: SKIPE DEBUGP
OUTSTR [ASCIZ/⊗INS*
/]
PUSHJ P,NETINS ; send INS
TELCMD [IAC IP IAC DM] ; and data mark
POPJ P,
; Send break
BREAK: TELCMD [IAC BRK]
POPJ P,
; Send abort output
ABORTO: CLRBFO
SKIPE DEBUGP
OUTSTR [ASCIZ/⊗INS*
/]
PUSHJ P,NETINS
TELCMD [IAC AO IAC DM]
POPJ P,
; Send are you there
RUTHER: TELCMD [IAC AYT]
POPJ P,
; Enter remote echo mode
RECHO: SKIPE ECHOP
POPJ P,
SETOM ECHOP
TELCMD [IAC DO ECHO]
POPJ P,
; Enter local echo mode
LECHO: SKIPN ECHOP
POPJ P,
SETOM ECHOP
TELCMD [IAC DONT ECHO]
POPJ P,
SUBTTL Connection command service routines
; Echo diddle without asking host
EOFF: SETOM ECHOP ? POPJ P,
EON: SETZM ECHOP ? POPJ P,
; Enter character-at-a-time mode
ECHATM: SETOM CHARMP
HRROI [001000,,(SPCBRK)]
TTYSET ; enter special activation mode
POPJ P,
; Leave character-at-a-time mode
LCHATM: SETZM CHARMP
HRROI [002000,,(SPCBRK)]
TTYSET ; leave special activation mode
POPJ P,
; Close connection
CLSCON: PUSHJ P,CLOSER
SETZM MONCMP ; forget being a monitor command
JRST TOPLEV
; Close connections and go away
PUNT: PUSHJ P,CLOSER ; close connections
BYEBYE: UNLOCK
EXIT
; Set escape character
ESCSET: INCHRW ? MOVEM ESCHAR ? POPJ P,
; MRC fooling around
DBUG: SETOM DEBUGP ? POPJ P,
NDBUG: SETZM DEBUGP ? POPJ P,
; Append file hacking
; Append to a file and always ask
APPEND: SKIPGE OUTFLP ; file open?
JRST [ OUTSTR [ASCIZ/Output file already open!
/]
POPJ P,]
OUTSTR [ASCIZ/Append file name: /]
PUSHJ P,GETFSP ; get filespec
SKIPN X,FSPBLK
POPJ P,
MOVEM X,OUTFLN
MOVE FSPBLK+1 ? MOVEM OUTEXT
MOVE FSPBLK+3 ? MOVEM OUTPPN
LOOKUP DSO,FSPBLK
JRST [ OUTSTR [ASCIZ/LOOKUP failed!
/]
SETZM OUTFLN ; toss away default
POPJ P,]
MOVE X,OUTPPN
MOVEM X,FSPBLK+3
ENTER DSO,FSPBLK
JRST [ OUTSTR [ASCIZ/ENTER failed!
/]
POPJ P,]
UGETF DSO, ; start appending
SETOM OUTFLP
POPJ P,
; Append but try using defaults
DAPPND: SKIPGE OUTFLP ; file open?
JRST [ OUTSTR [ASCIZ/Output file already open!
/]
POPJ P,]
SKIPN X,OUTFLN
JRST APPEND
MOVEM X,FSPBLK
MOVE X,OUTEXT
MOVEM X,FSPBLK+1
SETZM FSPBLK+2
MOVE X,OUTPPN
MOVEM X,FSPBLK+3
LOOKUP DSO,FSPBLK
JRST [ OUTSTR [ASCIZ/LOOKUP failed!
/]
SETZM OUTFLN ; toss away default
POPJ P,]
MOVE X,OUTPPN
MOVEM X,FSPBLK+3
ENTER DSO,FSPBLK
JRST [ OUTSTR [ASCIZ/ENTER failed!
/]
POPJ P,]
UGETF DSO, ; start appending
SETOM OUTFLP
OUTSTR [ASCIZ/Appending to file /]
MOVE X,OUTFLN
PUSHJ P,OUTSIX
OUTCHR [".]
MOVE X,OUTEXT
PUSHJ P,OUTSIX
OUTCHR ["[] ;]
HLLZ X,OUTPPN
PUSHJ P,OUTSIX
OUTCHR [",]
HRLZ X,OUTPPN
PUSHJ P,OUTSIX
OUTSTR [ASCIZ/]
/]
POPJ P,
; Output file hacking
; Close output file
CLSOFL: AOSE OUTFLP ; file open?
POPJ P,
CLOSE DSO, ; close output
OUTSTR [ASCIZ/Output file /]
MOVE X,OUTFLN
PUSHJ P,OUTSIX
OUTCHR [".]
MOVE X,OUTEXT
PUSHJ P,OUTSIX
OUTCHR ["[] ;]
HLLZ X,OUTPPN
PUSHJ P,OUTSIX
OUTCHR [",]
HRLZ X,OUTPPN
PUSHJ P,OUTSIX
OUTSTR [ASCIZ/] closed.
/]
POPJ P,
; Open output file
OPNOFL: SKIPGE OUTFLP ; file open?
JRST [ OUTSTR [ASCIZ/Output file already open!
/]
POPJ P,]
OUTSTR [ASCIZ/Output file name: /]
PUSHJ P,GETFSP ; get filespec
SKIPN X,FSPBLK
POPJ P,
MOVEM X,OUTFLN
MOVE FSPBLK+1 ? MOVEM OUTEXT
MOVE FSPBLK+3 ? MOVEM OUTPPN
ENTER DSO,FSPBLK
JRST [ OUTSTR [ASCIZ/ENTER failed!
/]
POPJ P,]
SETOM OUTFLP
POPJ P,
; Input file hacking
; Close input file
CLSIFL: AOSE INPFLP ; file open?
POPJ P,
CLOSE DSI, ; close input
OUTSTR [ASCIZ/Input file /]
MOVE X,INPFLN
PUSHJ P,OUTSIX
OUTCHR [".]
MOVE X,INPEXT
PUSHJ P,OUTSIX
OUTCHR ["[] ;]
HLLZ X,INPPPN
PUSHJ P,OUTSIX
OUTCHR [",]
HRLZ X,INPPPN
PUSHJ P,OUTSIX
OUTSTR [ASCIZ/] closed.
/]
SETZM SLOWFP
POPJ P,
; Open input file
OPNIFS: SETOM SLOWFP
OPNIFL: SKIPGE INPFLP ; file open?
JRST [ OUTSTR [ASCIZ/Input file already open!
/]
POPJ P,]
OUTSTR [ASCIZ/Input file name: /]
PUSHJ P,GETFSP ; get filespec
SKIPN X,FSPBLK
POPJ P,
MOVEM X,INPFLN
MOVE FSPBLK+1 ? MOVEM INPEXT
MOVE FSPBLK+3 ? MOVEM INPPPN
LOOKUP DSI,FSPBLK
JRST [ OUTSTR [ASCIZ/LOOKUP failed!
/]
SETZM SLOWFP
POPJ P,]
SETOM INPFLP
POPJ P,
SUBTTL Call DDT if there is a DDT present
DDTCAL: SKIPN JOBDDT
POPJ P, ; no DDT!
OUTSTR [ASCIZ/You're in DDT.
/]
HRROI [002000,,(SPCBRK)]
SKIPE CHARMP
TTYSET ; leave special activation mode
PTJOBX [0 ? 4]
PUSHJ P,@JOBDDT ; enter DDT
PTJOBX [0 ? 3]
HRROI [001000,,(SPCBRK)]
SKIPE CHARMP
TTYSET ; enter special activation mode
POPJ P,
SUBTTL Filespec input routine.
; Smashes X, Y, and Z; sets up FSPBLK.
GETFSP: HRROI [002000,,(SPCBRK)]
SKIPE CHARMP
TTYSET ; leave special activation mode
PTJOBX [0 ? 4] ; echo filespec
SETZM FSPBLK ? SETZM FSPBLK+1 ? SETZM FSPBLK+2
SETZ X,
DSKPPN X,
MOVEM X,FSPBLK+3
PUSHJ P,GETSIX ; get file name
JUMPE X,FSPLUZ
MOVEM X,FSPBLK ; got file name
CAIE Y,".
JRST NOEXT
PUSHJ P,GETSIX ; try for extension
MOVEM X,FSPBLK+1
NOEXT: CAIN Y,↑J
JRST FSPDUN
CAIE Y,"[ ; must be a PPN
JRST FSPLUZ
PUSHJ P,GETSIX
TRNE X,-1
JRST FSPLUZ
TLNN X,77
JUMPN X,[LSH X,-6 ? JRST .-1]
SKIPE X
HLLM X,FSPBLK+3
CAIE Y,",
JRST FSPEOS
PUSHJ P,GETSIX
TRNE X,-1
JRST FSPLUZ
TLNN X,77
JUMPN X,[LSH X,-6 ? JRST .-1]
SKIPE X
HLRM X,FSPBLK+3
FSPEOS: CAIN Y,"]
INCHWL Y
CAIN Y,↑M
INCHWL Y
CAIE Y,↑J
JRST FSPLUZ
FSPDUN: PTJOBX [0 ? 3]
HRROI [001000,,(SPCBRK)]
SKIPE CHARMP
TTYSET ; enter special activation mode
POPJ P,
FSPLUZ: CLRBFI
CAIN Y,175
JRST [ SETZM FSPBLK ; sorry defaulters
OUTSTR [ASCIZ/ Aborted.
/]
JRST FSPDUN]
OUTSTR [ASCIZ/Invalid file specification. Try again: /]
JRST GETFSP
SUBTTL Sixbit & numeric TTY I/O
; Sixbit output routine. Takes a word in X, smashes Y, flushes spaces.
OUTSIX: SETZ Y,
ROTC X,6
JUMPE Y,OUTSX1
ADDI Y,"A-'A
OUTCHR Y
OUTSX1: JUMPN X,OUTSIX
POPJ P,
; Sixbit input routine. Inputs a sixbit word in X, smashes Y and Z.
GETSIX: SETZ X,
MOVE Z,[440600,,X]
GETSX1: INCHWL Y
CAIN Y,↑M
INCHWL Y
CAIL Y,"a ; convert to upper case
CAILE Y,"z
CAIA
SUBI Y,"a-"A
CAIL Y,"0 ; only allow alphanumerics
CAILE Y,"Z
POPJ P,
CAILE Y,"9
CAIL Y,"A
CAIA
POPJ P,
SUBI Y,"A-'A ; convert to sixbit
TRNN X,77 ; don't go beyond last byte
IDPB Y,Z
JRST GETSX1
; Super winning numeric input routine. Numbers are parsed as both octal and
; decimal, unless either (a) an 8 or 9 appears in the number, or (b) the number
; is followed by a decimal point.
SWINIR: SETZB A,B ; A ← octal number, B ← decimal
SWINR1: CAIL X,"8 ; if can't be octal, A ← 1
SETO A,
JUMPL A,SWINR2
LSH A,3
ADDI A,-"0(X) ; bring in next octal digit
SWINR2: IMULI B,10.
ADDI B,-"0(X) ; bring in next decimal digit
ILDB X,Y
CAIN X,". ; decimal point ends spec and forces decimal
JRST [ SETO A,
ILDB X,Y
POPJ P,]
CAIL X,"0
CAIL X,"9
POPJ P, ; non-numeric, return
JRST SWINR1
...LIT: CONSTANTS
END TELNET